home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / C / Applications / Tcl-Tk 8.0 / Pre-installed version / MoreFiles 1.4.3 / Sources / DirectoryCopy.c next >
Encoding:
C/C++ Source or Header  |  1996-08-24  |  20.2 KB  |  610 lines  |  [TEXT/MPS ]

  1. /*
  2. **    Apple Macintosh Developer Technical Support
  3. **
  4. **    DirectoryCopy: A robust, general purpose directory copy routine.
  5. **
  6. **    by Jim Luther, Apple Developer Technical Support Emeritus
  7. **
  8. **    File:        DirectoryCopy.c
  9. **
  10. **    Copyright © 1992-1996 Apple Computer, Inc.
  11. **    All rights reserved.
  12. **
  13. **    You may incorporate this sample code into your applications without
  14. **    restriction, though the sample code has been provided "AS IS" and the
  15. **    responsibility for its operation is 100% yours.  However, what you are
  16. **    not permitted to do is to redistribute the source as "DSC Sample Code"
  17. **    after having made changes. If you're going to re-distribute the source,
  18. **    we require that you make it clear in the source that the code was
  19. **    descended from Apple Sample Code, but that you've made changes.
  20. */
  21.  
  22. #include <Types.h>
  23. #include <Errors.h>
  24. #include <Memory.h>
  25. #include <Files.h>
  26. #include <Script.h>
  27.  
  28. #define    __COMPILINGMOREFILES
  29.  
  30. #include "MoreFiles.h"
  31. #include "MoreFilesExtras.h"
  32. #include "MoreDesktopMgr.h"
  33. #include "FileCopy.h"
  34. #include "DirectoryCopy.h"
  35.  
  36. /*****************************************************************************/
  37.  
  38. /* local constants */
  39.  
  40. enum
  41. {
  42.     dirCopyBigCopyBuffSize  = 0x00004000,
  43.     dirCopyMinCopyBuffSize  = 0x00000200
  44. };
  45.  
  46.  
  47. /*****************************************************************************/
  48.  
  49. /* local data structures */
  50.  
  51. /* The EnumerateGlobals structure is used to minimize the amount of
  52. ** stack space used when recursively calling CopyLevel and to hold
  53. ** global information that might be needed at any time. */
  54.  
  55. #if PRAGMA_ALIGN_SUPPORTED
  56. #pragma options align=mac68k
  57. #endif
  58. struct EnumerateGlobals
  59. {
  60.     Ptr            copyBuffer;            /* pointer to buffer used for file copy operations */
  61.     long        bufferSize;            /* the size of the copy buffer */
  62.     CopyErrProcPtr errorHandler;    /* pointer to error handling function */
  63.     CopyFilterProcPtr copyFilterProc; /* pointer to filter function */
  64.     OSErr        error;                /* temporary holder of results - saves 2 bytes of stack each level */
  65.     Boolean        bailout;            /* set to true to by error handling function if fatal error */
  66.     short        destinationVRefNum;    /* the destination vRefNum */
  67.     Str63        itemName;            /* the name of the current item */
  68.     CInfoPBRec    myCPB;                /* the parameter block used for PBGetCatInfo calls */
  69. };
  70. #if PRAGMA_ALIGN_SUPPORTED
  71. #pragma options align=reset
  72. #endif
  73.  
  74. typedef struct EnumerateGlobals EnumerateGlobals;
  75. typedef EnumerateGlobals *EnumerateGlobalsPtr;
  76.  
  77.  
  78. /* The PreflightGlobals structure is used to minimize the amount of
  79. ** stack space used when recursively calling GetLevelSize and to hold
  80. ** global information that might be needed at any time. */
  81.  
  82. #if PRAGMA_ALIGN_SUPPORTED
  83. #pragma options align=mac68k
  84. #endif
  85. struct PreflightGlobals
  86. {
  87.     OSErr            result;                /* temporary holder of results - saves 2 bytes of stack each level */
  88.     Str63            itemName;            /* the name of the current item */
  89.     CInfoPBRec        myCPB;                /* the parameter block used for PBGetCatInfo calls */
  90.  
  91.     unsigned short    dstBlksPerAllocBlk;    /* the number of 512 byte blocks per allocation block on destination */
  92.     unsigned short    allocBlksNeeded;    /* the total number of allocation blocks needed  */
  93.  
  94.     unsigned short    tempBlocks;            /* temporary storage for calculations (save some stack space)  */
  95.     CopyFilterProcPtr copyFilterProc;    /* pointer to filter function */
  96. };
  97. #if PRAGMA_ALIGN_SUPPORTED
  98. #pragma options align=reset
  99. #endif
  100.  
  101. typedef struct PreflightGlobals PreflightGlobals;
  102. typedef PreflightGlobals *PreflightGlobalsPtr;
  103.  
  104. /*****************************************************************************/
  105.  
  106. /* static prototypes */
  107.  
  108. static    void    GetLevelSize(long currentDirID,
  109.                              PreflightGlobalsPtr theGlobals);
  110.  
  111. static    OSErr    PreflightDirectoryCopySpace(short srcVRefNum,
  112.                                             long srcDirID,
  113.                                             short dstVRefNum,
  114.                                             CopyFilterProcPtr copyFilterProc,
  115.                                             Boolean *spaceOK);
  116.  
  117. static    void    CopyLevel(long sourceDirID,
  118.                           long dstDirID,
  119.                           EnumerateGlobalsPtr theGlobals);
  120.                           
  121. /*****************************************************************************/
  122.  
  123. static    void    GetLevelSize(long currentDirID,
  124.                              PreflightGlobalsPtr theGlobals)
  125. {
  126.     short    index = 1;
  127.     
  128.     do
  129.     {
  130.         theGlobals->myCPB.dirInfo.ioFDirIndex = index;
  131.         theGlobals->myCPB.dirInfo.ioDrDirID = currentDirID;    /* we need to do this every time */
  132.                                                             /* through, since GetCatInfo  */
  133.                                                             /* returns ioFlNum in this field */
  134.         theGlobals->result = PBGetCatInfoSync(&theGlobals->myCPB);
  135.         if ( theGlobals->result == noErr )
  136.         {
  137.             if ( (theGlobals->copyFilterProc == NULL) ||
  138.                  CallCopyFilterProc(theGlobals->copyFilterProc, &theGlobals->myCPB) ) /* filter if filter proc was supplied */
  139.             {
  140.                 /* Either there's no filter proc OR the filter proc says to use this item */
  141.                 if ( (theGlobals->myCPB.dirInfo.ioFlAttrib & ioDirMask) != 0 )
  142.                 {
  143.                     /* we have a directory */
  144.                     
  145.                     GetLevelSize(theGlobals->myCPB.dirInfo.ioDrDirID, theGlobals); /* recurse */
  146.                     theGlobals->result = noErr; /* clear error return on way back */
  147.                 }
  148.                 else
  149.                 {
  150.                     /* we have a file - add its allocation blocks to allocBlksNeeded */
  151.                     
  152.                     /* get number of 512-byte blocks needed for data fork */
  153.                     theGlobals->tempBlocks = ((unsigned long)theGlobals->myCPB.hFileInfo.ioFlLgLen % 512) ?
  154.                                                 (((unsigned long)theGlobals->myCPB.hFileInfo.ioFlLgLen >> 9) + 1) :
  155.                                                 ((unsigned long)theGlobals->myCPB.hFileInfo.ioFlLgLen >> 9);
  156.                     /* now, calculate number of new allocation blocks needed */
  157.                     theGlobals->allocBlksNeeded += (theGlobals->tempBlocks % theGlobals->dstBlksPerAllocBlk) ?
  158.                                                     ((theGlobals->tempBlocks / theGlobals->dstBlksPerAllocBlk) + 1) :
  159.                                                     (theGlobals->tempBlocks / theGlobals->dstBlksPerAllocBlk);
  160.                     
  161.                     /* get number of 512-byte blocks needed for resource fork */
  162.                     theGlobals->tempBlocks = ((unsigned long)theGlobals->myCPB.hFileInfo.ioFlRLgLen % 512) ?
  163.                                                 (((unsigned long)theGlobals->myCPB.hFileInfo.ioFlRLgLen >> 9) + 1) :
  164.                                                 ((unsigned long)theGlobals->myCPB.hFileInfo.ioFlRLgLen >> 9);
  165.                     /* now, calculate number of new allocation blocks needed */
  166.                     theGlobals->allocBlksNeeded += (theGlobals->tempBlocks % theGlobals->dstBlksPerAllocBlk) ?
  167.                                                     ((theGlobals->tempBlocks / theGlobals->dstBlksPerAllocBlk) + 1) :
  168.                                                     (theGlobals->tempBlocks / theGlobals->dstBlksPerAllocBlk);
  169.                 }
  170.             }
  171.         }
  172.         ++index;
  173.     } while ( theGlobals->result == noErr );
  174. }
  175.  
  176. /*****************************************************************************/
  177.  
  178. static    OSErr    PreflightDirectoryCopySpace(short srcVRefNum,
  179.                                             long srcDirID,
  180.                                             short dstVRefNum,
  181.                                             CopyFilterProcPtr copyFilterProc,
  182.                                             Boolean *spaceOK)
  183. {
  184.     HParamBlockRec pb;
  185.     OSErr error;
  186.     unsigned short dstFreeBlocks;
  187.     PreflightGlobals theGlobals;
  188.     
  189.     /* Get the number of 512 byte blocks per allocation block and */
  190.     /* number of free allocation blocks on the destination volume */
  191.     error = GetVolumeInfoNoName(NULL, dstVRefNum, &pb);
  192.     if ( error == noErr )
  193.     {
  194.         dstFreeBlocks = (unsigned short)pb.volumeParam.ioVFrBlk;
  195.         
  196.         /* get allocation block size (always multiple of 512) and divide by 512
  197.           to get number of 512-byte blocks per allocation block */
  198.         theGlobals.dstBlksPerAllocBlk = ((unsigned long)pb.volumeParam.ioVAlBlkSiz >> 9);
  199.         
  200.         theGlobals.allocBlksNeeded = 0;
  201.  
  202.         theGlobals.myCPB.dirInfo.ioNamePtr = theGlobals.itemName;
  203.         theGlobals.myCPB.dirInfo.ioVRefNum = srcVRefNum;
  204.         
  205.         theGlobals.copyFilterProc = copyFilterProc;
  206.         
  207.         GetLevelSize(srcDirID, &theGlobals);
  208.         
  209.         /* Is there enough room on the destination volume for the source file? */
  210.         *spaceOK = (theGlobals.allocBlksNeeded <= dstFreeBlocks);
  211.     }
  212.     return ( error );
  213. }
  214.  
  215. /*****************************************************************************/
  216.  
  217. static    void    CopyLevel(long sourceDirID,
  218.                           long dstDirID,
  219.                           EnumerateGlobalsPtr theGlobals)
  220. {
  221.     long currentSrcDirID;
  222.     long newDirID;
  223.     short index = 1;
  224.     
  225.     do
  226.     {    
  227.         /* Get next source item at the current directory level */
  228.         
  229.         theGlobals->myCPB.dirInfo.ioFDirIndex = index;
  230.         theGlobals->myCPB.dirInfo.ioDrDirID = sourceDirID;
  231.         theGlobals->error = PBGetCatInfoSync(&theGlobals->myCPB);        
  232.  
  233.         if ( theGlobals->error == noErr )
  234.         {
  235.             if ( (theGlobals->copyFilterProc == NULL) ||
  236.                  CallCopyFilterProc(theGlobals->copyFilterProc, &theGlobals->myCPB) ) /* filter if filter proc was supplied */
  237.             {
  238.                 /* Either there's no filter proc OR the filter proc says to use this item */
  239.  
  240.                 /* We have an item.  Is it a file or directory? */
  241.                 if ( (theGlobals->myCPB.hFileInfo.ioFlAttrib & ioDirMask) != 0 )
  242.                 {
  243.                     /* We have a directory */
  244.                     
  245.                     /* Create a new directory at the destination. No errors allowed! */
  246.                     theGlobals->error = DirCreate(theGlobals->destinationVRefNum, dstDirID, theGlobals->itemName, &newDirID);
  247.                     if ( theGlobals->error == noErr )
  248.                     {
  249.                         /* Save the current source directory ID where we can get it when we come back
  250.                         ** from recursion land. */
  251.                         currentSrcDirID = theGlobals->myCPB.dirInfo.ioDrDirID;
  252.                         
  253.                         /* Dive again (copy the directory level we just found below this one) */
  254.                         CopyLevel(theGlobals->myCPB.dirInfo.ioDrDirID, newDirID, theGlobals);
  255.                         
  256.                         if ( !theGlobals->bailout )
  257.                         {
  258.                             /* Copy comment from old to new directory. */
  259.                             /* Ignore the result because we really don't care if it worked or not. */
  260.                             (void) DTCopyComment(theGlobals->myCPB.dirInfo.ioVRefNum, currentSrcDirID, NULL, theGlobals->destinationVRefNum, newDirID, NULL);
  261.                             
  262.                             /* Copy directory attributes (dates, etc.) to newDirID. */
  263.                             /* No errors allowed */
  264.                             theGlobals->error = CopyFileMgrAttributes(theGlobals->myCPB.dirInfo.ioVRefNum, currentSrcDirID, NULL, theGlobals->destinationVRefNum, newDirID, NULL, true);
  265.                             
  266.                             /* handle any errors from CopyFileMgrAttributes */
  267.                             if ( theGlobals->error != noErr )
  268.                             {
  269.                                 if ( theGlobals->errorHandler != NULL )
  270.                                 {
  271.                                     theGlobals->bailout =  CallCopyErrProc(theGlobals->errorHandler, theGlobals->error, copyDirFMAttributesOp,
  272.                                                             theGlobals->myCPB.dirInfo.ioVRefNum, currentSrcDirID, NULL,
  273.                                                             theGlobals->destinationVRefNum, newDirID, NULL);
  274.                                 }
  275.                                 else
  276.                                 {
  277.                                     /* If you don't handle the errors with an error handler, */
  278.                                     /* then the copy stops here. */
  279.                                     theGlobals->bailout = true;
  280.                                 }
  281.                             }
  282.                         }
  283.                     }
  284.                     else    /* error handling for DirCreate */
  285.                     {
  286.                         if ( theGlobals->errorHandler != NULL )
  287.                         {
  288.                             theGlobals->bailout = CallCopyErrProc(theGlobals->errorHandler, theGlobals->error, dirCreateOp,
  289.                                                         theGlobals->myCPB.dirInfo.ioVRefNum, currentSrcDirID, NULL,
  290.                                                         theGlobals->destinationVRefNum, dstDirID, theGlobals->itemName);
  291.                         }
  292.                         else
  293.                         {
  294.                             /* If you don't handle the errors with an error handler, */
  295.                             /* then the copy stops here. */
  296.                             theGlobals->bailout = true;
  297.                         }
  298.                     }
  299.                     
  300.                     if ( !theGlobals->bailout )
  301.                     {
  302.                         /* clear error return on way back if we aren't bailing out */
  303.                         theGlobals->error = noErr;
  304.                     }
  305.                 }
  306.                 else
  307.                 {
  308.                     /* We have a file, so copy it */
  309.                     
  310.                     theGlobals->error = FileCopy(theGlobals->myCPB.hFileInfo.ioVRefNum,
  311.                                                  theGlobals->myCPB.hFileInfo.ioFlParID,
  312.                                                  theGlobals->itemName,
  313.                                                  theGlobals->destinationVRefNum,
  314.                                                  dstDirID,
  315.                                                  NULL,
  316.                                                  NULL,
  317.                                                  theGlobals->copyBuffer,
  318.                                                  theGlobals->bufferSize,
  319.                                                  false);
  320.                             
  321.                     /* handle any errors from FileCopy */
  322.                     if ( theGlobals->error != noErr )
  323.                     {
  324.                         if ( theGlobals->errorHandler != NULL )
  325.                         {
  326.                             theGlobals->bailout = CallCopyErrProc(theGlobals->errorHandler, theGlobals->error, fileCopyOp,
  327.                                                     theGlobals->myCPB.hFileInfo.ioVRefNum, theGlobals->myCPB.hFileInfo.ioFlParID, theGlobals->itemName,
  328.                                                     theGlobals->destinationVRefNum, dstDirID, NULL);
  329.                             if ( !theGlobals->bailout )
  330.                             {
  331.                                 /* If the CopyErrProc handled the problem, clear the error here */
  332.                                 theGlobals->error = noErr;
  333.                             }
  334.                         }
  335.                         else
  336.                         {
  337.                             /* If you don't handle the errors with an error handler, */
  338.                             /* then the copy stops here. */
  339.                             theGlobals->bailout = true;
  340.                         }
  341.                     }
  342.                 }
  343.             }
  344.         }
  345.         else
  346.         {    /* error handling for PBGetCatInfo */
  347.             /* it's normal to get a fnfErr when indexing; that only means you've hit the end of the directory */
  348.             if ( theGlobals->error != fnfErr )
  349.             {
  350.                 if ( theGlobals->errorHandler != NULL )
  351.                 { 
  352.                     theGlobals->bailout = CallCopyErrProc(theGlobals->errorHandler, theGlobals->error, getNextItemOp,
  353.                                             theGlobals->myCPB.dirInfo.ioVRefNum, sourceDirID, NULL, 0, 0, NULL);
  354.                     if ( !theGlobals->bailout )
  355.                     {
  356.                         /* If the CopyErrProc handled the problem, clear the error here */
  357.                         theGlobals->error = noErr;
  358.                     }
  359.                 }
  360.                 else
  361.                 {
  362.                     /* If you don't handle the errors with an error handler, */
  363.                     /* then the copy stops here. */
  364.                     theGlobals->bailout = true;
  365.                 }
  366.             }
  367.         }
  368.         ++index; /* prepare to get next item */
  369.     } while ( (theGlobals->error == noErr) && (!theGlobals->bailout) ); /* time to fall back a level? */
  370. }
  371.  
  372. /*****************************************************************************/
  373.  
  374. pascal    OSErr    FilteredDirectoryCopy(short srcVRefNum,
  375.                                       long srcDirID,
  376.                                       StringPtr srcName,
  377.                                       short dstVRefNum,
  378.                                       long dstDirID,
  379.                                       StringPtr dstName,
  380.                                       void *copyBufferPtr,
  381.                                       long copyBufferSize,
  382.                                       Boolean preflight,
  383.                                       CopyErrProcPtr copyErrHandler,
  384.                                       CopyFilterProcPtr copyFilterProc)
  385. {
  386.     EnumerateGlobals theGlobals;
  387.     Boolean    isDirectory;
  388.     OSErr    error;
  389.     Boolean ourCopyBuffer = false;
  390.     Str63    srcDirName, oldDiskName;
  391.     Boolean spaceOK;            
  392.     
  393.     /* Make sure a copy buffer is allocated. */
  394.     if ( copyBufferPtr == NULL )
  395.     {
  396.         /* The caller didn't supply a copy buffer so grab one from the application heap.
  397.         ** Try to get a big copy buffer, if we can't, try for a 512-byte buffer.
  398.         ** If 512 bytes aren't available, we're in trouble. */
  399.         copyBufferSize = dirCopyBigCopyBuffSize;
  400.         copyBufferPtr = NewPtr(copyBufferSize);
  401.         if ( copyBufferPtr == NULL )
  402.         {
  403.             copyBufferSize = dirCopyMinCopyBuffSize;
  404.             copyBufferPtr = NewPtr(copyBufferSize);
  405.             if ( copyBufferPtr == NULL )
  406.                 return ( memFullErr );
  407.         }
  408.         ourCopyBuffer = true;
  409.     }
  410.     
  411.     /* Get the real dirID where we're copying from and make sure it is a directory. */
  412.     error = GetDirectoryID(srcVRefNum, srcDirID, srcName, &srcDirID, &isDirectory);
  413.     if ( error != noErr )
  414.         goto ErrorExit;
  415.     if ( !isDirectory )
  416.     {
  417.         error = dirNFErr;
  418.         goto ErrorExit;
  419.     }
  420.     
  421.     /* Special case destination if it is the root parent directory. */
  422.     /* Since you can't create the root directory, this is needed if */
  423.     /* you want to copy a directory's content to a disk's root directory. */
  424.     if ( (dstDirID == fsRtParID) && (dstName == NULL) )
  425.     {
  426.         dstDirID = fsRtParID;
  427.         isDirectory = true;
  428.         error = noErr;
  429.     }
  430.     else
  431.     {
  432.         /*  Get the real dirID where we're going to put the copy and make sure it is a directory. */
  433.         error = GetDirectoryID(dstVRefNum, dstDirID, dstName, &dstDirID, &isDirectory);
  434.         if ( error != noErr )
  435.             goto ErrorExit;
  436.         if ( !isDirectory )
  437.         {
  438.             error =  dirNFErr;
  439.             goto ErrorExit;
  440.         }
  441.     }
  442.     
  443.     /* Get the real vRefNum of both the source and destination */
  444.     error = DetermineVRefNum(srcName, srcVRefNum, &srcVRefNum);
  445.     if ( error != noErr )
  446.         goto ErrorExit;
  447.     error = DetermineVRefNum(dstName, dstVRefNum, &dstVRefNum);
  448.     if ( error != noErr )
  449.         goto ErrorExit;
  450.     
  451.     if ( preflight )
  452.     {
  453.         error = PreflightDirectoryCopySpace(srcVRefNum, srcDirID, dstVRefNum, copyFilterProc, &spaceOK);
  454.         if ( error != noErr )
  455.             goto ErrorExit;
  456.         if ( !spaceOK )
  457.         {
  458.             error = dskFulErr; /* not enough room on destination */
  459.             goto ErrorExit;
  460.         }
  461.     }
  462.  
  463.     /* Create the new directory in the destination directory with the */
  464.     /* same name as the source directory. */
  465.     error = GetDirName(srcVRefNum, srcDirID, srcDirName);
  466.     if ( error != noErr )
  467.         goto ErrorExit;
  468.     
  469.     /* Again, special case destination if the destination is the */
  470.     /* root parent directory. This time, we'll rename the disk to */
  471.     /* the source directory name. */
  472.     if ( dstDirID == fsRtParID )
  473.     {
  474.         /* Get the current name of the destination disk */
  475.         error = GetDirName(dstVRefNum, fsRtDirID, oldDiskName);
  476.         if ( error == noErr )    
  477.         {
  478.             /* Shorten the name if it's too long to be the volume name */
  479.             TruncPString(srcDirName, srcDirName, 27);
  480.             
  481.             /* Rename the disk */
  482.             error = HRename(dstVRefNum, fsRtParID, oldDiskName, srcDirName);
  483.             /* and copy to the root directory */
  484.             dstDirID = fsRtDirID;
  485.         }
  486.     }
  487.     else
  488.     {
  489.         error = DirCreate(dstVRefNum, dstDirID, srcDirName, &dstDirID);
  490.     }
  491.     if ( error != noErr )
  492.     {
  493.         /* handle any errors from DirCreate */
  494.         if ( copyErrHandler != NULL )
  495.         {
  496.             if ( CallCopyErrProc(copyErrHandler, error, dirCreateOp,
  497.                                                     srcVRefNum, srcDirID, NULL,
  498.                                                     dstVRefNum, dstDirID, srcDirName) )
  499.             {
  500.                 goto ErrorExit;
  501.             }
  502.             else
  503.             {
  504.                 /* If the CopyErrProc handled the problem, clear the error here */
  505.                 /* and continue */
  506.                 error = noErr;
  507.             }
  508.         }
  509.         else
  510.         {
  511.             /* If you don't handle the errors with an error handler, */
  512.             /* then the copy stops here. */
  513.             goto ErrorExit;
  514.         }
  515.     }
  516.     
  517.     /* dstDirID is now the newly created directory! */
  518.         
  519.     /* Set up the globals we need to access from the recursive routine. */
  520.     theGlobals.copyBuffer = (Ptr)copyBufferPtr;
  521.     theGlobals.bufferSize = copyBufferSize;
  522.     theGlobals.destinationVRefNum = dstVRefNum; /* so we can get to it always */
  523.     theGlobals.myCPB.hFileInfo.ioNamePtr = (StringPtr)&theGlobals.itemName;
  524.     theGlobals.myCPB.hFileInfo.ioVRefNum = srcVRefNum;
  525.     theGlobals.errorHandler = copyErrHandler;
  526.     theGlobals.bailout = false;
  527.     theGlobals.copyFilterProc =  copyFilterProc;
  528.         
  529.     /* Here we go into recursion land... */
  530.     CopyLevel(srcDirID, dstDirID, &theGlobals);
  531.     error = theGlobals.error;    /* get the result */
  532.     
  533.     if ( !theGlobals.bailout )
  534.     {
  535.         /* Copy comment from source to destination directory. */
  536.         /* Ignore the result because we really don't care if it worked or not. */
  537.         (void) DTCopyComment(srcVRefNum, srcDirID, NULL, dstVRefNum, dstDirID, NULL);
  538.         
  539.         /* Copy the File Manager attributes */
  540.         error = CopyFileMgrAttributes(srcVRefNum, srcDirID, NULL,
  541.                     dstVRefNum, dstDirID, NULL, true);
  542.         
  543.         /* handle any errors from CopyFileMgrAttributes */
  544.         if ( (error != noErr) && (copyErrHandler != NULL) )
  545.             theGlobals.bailout = CallCopyErrProc(copyErrHandler, error, copyDirFMAttributesOp,
  546.                                                 srcVRefNum, srcDirID, NULL,
  547.                                                 dstVRefNum, dstDirID, NULL);
  548.     }
  549.  
  550. ErrorExit:
  551.     /* Get rid of the copy buffer if we allocated it. */
  552.     if ( ourCopyBuffer )
  553.         DisposePtr((Ptr)copyBufferPtr);
  554.  
  555.     return ( error );
  556. }
  557.  
  558. /*****************************************************************************/
  559.  
  560. pascal    OSErr    DirectoryCopy(short srcVRefNum,
  561.                               long srcDirID,
  562.                               StringPtr srcName,
  563.                               short dstVRefNum,
  564.                               long dstDirID,
  565.                               StringPtr dstName,
  566.                               void *copyBufferPtr,
  567.                               long copyBufferSize,
  568.                               Boolean preflight,
  569.                               CopyErrProcPtr copyErrHandler)
  570. {
  571.     return ( FilteredDirectoryCopy(srcVRefNum, srcDirID, srcName,
  572.                                    dstVRefNum, dstDirID, dstName,
  573.                                    copyBufferPtr, copyBufferSize, preflight,
  574.                                    copyErrHandler, NULL) );
  575. }
  576.  
  577. /*****************************************************************************/
  578.  
  579. pascal    OSErr    FSpFilteredDirectoryCopy(const FSSpec *srcSpec,
  580.                                          const FSSpec *dstSpec,
  581.                                          void *copyBufferPtr,
  582.                                          long copyBufferSize,
  583.                                          Boolean preflight,
  584.                                          CopyErrProcPtr copyErrHandler,
  585.                                          CopyFilterProcPtr copyFilterProc)
  586. {
  587.     return ( FilteredDirectoryCopy(srcSpec->vRefNum, srcSpec->parID, (StringPtr)srcSpec->name,
  588.                                    dstSpec->vRefNum, dstSpec->parID, (StringPtr)dstSpec->name,
  589.                                    copyBufferPtr, copyBufferSize, preflight,
  590.                                    copyErrHandler, copyFilterProc) );
  591. }
  592.  
  593. /*****************************************************************************/
  594.  
  595. pascal    OSErr    FSpDirectoryCopy(const FSSpec *srcSpec,
  596.                                  const FSSpec *dstSpec,
  597.                                  void *copyBufferPtr,
  598.                                  long copyBufferSize,
  599.                                  Boolean preflight,
  600.                                  CopyErrProcPtr copyErrHandler)
  601. {
  602.     return ( FilteredDirectoryCopy(srcSpec->vRefNum, srcSpec->parID, (StringPtr)srcSpec->name,
  603.                                    dstSpec->vRefNum, dstSpec->parID, (StringPtr)dstSpec->name,
  604.                                    copyBufferPtr, copyBufferSize, preflight,
  605.                                    copyErrHandler, NULL) );
  606. }
  607.  
  608. /*****************************************************************************/
  609.  
  610.